/**************************************************************************//**
  \file  sp_driver.s

  \brief Implementation of self programming functions.

  \author
      Atmel Corporation: http://www.atmel.com \n
      Support email: avr@atmel.com

    Copyright (c) 2008-2013, Atmel Corporation. All rights reserved.
    Licensed under Atmel's Limited License Agreement (BitCloudTM).

  \internal
    History:
      13/05/09 A. Khromykh - Created

********************************************************************************/

#include <avr/io.h>

#define SREG_IO  0x3F
#define RAMPZ_IO 0x3B
#define SPMCSR_IO 0x37

/*******************************************************************************/
.section .text
/*******************************************************************************
This routine enables RWW section.
Parameters:
  none
Returns:
  none.
*******************************************************************************/
.global SP_RWWSectionEnable

SP_RWWSectionEnable:
    in	  r19, RAMPZ_IO                        ; Save RAMPZ, which is restored in SP_CommonSPM.
	ldi	  r20, (1 << RWWSRE)                   ; Prepare NVM command in R20.  (1 << RWWSRE)
	jmp	  SP_CommonSPM                         ; Jump to common SPM code.

/*******************************************************************************
This routine writes the word from R23:R22 into the Flash page buffer at
address R25:R24.
Parameters:
  R25:R24 - Byte address into Flash page.
  R23:R22 - Word to write.
Returns:
  none.
*******************************************************************************/
.global SP_LoadFlashWord
SP_LoadFlashWord:
	in	  r19, RAMPZ_IO                            ; Save RAMPZ, which is restored in SP_CommonSPM.
	movw  r0,  r22                             ; Prepare flash word in R1:R0.
	clr   r20                                  ; prepare command for SPM
	jmp	  SP_CommonSPM                         ; Jump to common SPM code.

/*******************************************************************************
This routine erases the page buffer to the
Flash page at address R25:R24:R23:R22 in the application section. The address
can point anywhere inside the page.
Parameters:
  R25:R24:R23:R22 - Byte address into Flash page.
Returns:
  none.
*******************************************************************************/
.global SP_EraseApplicationPage
SP_EraseApplicationPage:
	in	  r19, RAMPZ_IO                         ; Save RAMPZ, which is restored in SP_CommonSPM.
	out	  RAMPZ_IO, r24                         ; Load RAMPZ with the MSB of the address.
	movw  r24, r22                              ; Move low bytes of address to ZH:ZL from R23:R22
	ldi	  r20, (1 << PGERS)                     ; Prepare SPM command in R20. (1 << PGERS)
	jmp	  SP_CommonSPM                          ; Jump to common SPM code.

/*******************************************************************************
This routine writes the page buffer to the
Flash page at address R25:R24:R23:R22 in the application section. The address
can point anywhere inside the page.
Parameters:
  R25:R24:R23:R22 - Byte address into Flash page.
Returns:
  none.
*******************************************************************************/
.global SP_WriteApplicationPage
SP_WriteApplicationPage:
	in	  r19, RAMPZ_IO                         ; Save RAMPZ, which is restored in SP_CommonSPM.
	out	  RAMPZ_IO, r24                         ; Load RAMPZ with the MSB of the address.
	movw  r24, r22                              ; Move low bytes of address to ZH:ZL from R23:R22
	ldi	  r20, (1 << PGWRT)                       ; Prepare NVM command in R20.  (1 << PGWRT)
	jmp	  SP_CommonSPM                          ; Jump to common SPM code.

/*******************************************************************************
This routine is called by several other routines, and contains common code
for executing an SPM command, including the return statement itself.

If the operation (SPM command) requires the R1:R0 registers to be
prepared, this must be done before jumping to this routine.
Parameters:
  R1:R0    - Optional input to SPM command.
  R25:R24  - Low bytes of Z pointer.
  R20      - SPM Command code.
Returns:
  none.
*******************************************************************************/
SP_CommonSPM:
	in	  r18, SPMCSR_IO						; load SPMCSR to reg
	sbrc  r18, SPMEN							; SPMEN bit for completition	
	rjmp  SP_CommonSPM							; jump if SPMEN bit in reg is set, wait to clear

	movw  r30, r24                              ; Load R25:R24 into Z.
	ori   r20, (1 << SPMEN)                     ; prepare command for SPM
	out	  SPMCSR_IO, r20                        ; Load prepared command into SPMCSR register.
	spm                                         ; Self-program.
	clr	  r1                                    ; Clear R1 for GCC _zero_reg_ to function properly.
	out	  RAMPZ_IO, r19                         ; Restore RAMPZ register.
	ret

/*******************************************************************************
Reads byte from internal flash
Parameters:
  R25:R24:R23:R22 - Byte address into flash.
Returns:
  R24 - read byte from flash.
*******************************************************************************/
/*
.global SP_ReadInternalFlashByte

SP_ReadInternalFlashByte:
    in    r25,  RAMPZ_IO                         ; Save RAMPZ.
    out	  RAMPZ_IO, r24                          ; Load RAMPZ with the MSB of the address.
    movw  r30,  r22                              ; Move low bytes of address to ZH:ZL from R23:R22
    elpm  r24,  Z                                ; Extended load program memory from Z address
    out	  RAMPZ_IO, r25                          ; Restore RAMPZ register.
    ret                                          ; return from function
*/
/*******************************************************************************
Reads word from internal flash
Parameters:
  R25:R24:R23:R22 - Byte address into flash.
Returns:
  R25:R24 - read word from flash.
*******************************************************************************/
/*
.global SP_ReadInternalFlashWord

SP_ReadInternalFlashWord:
	in		r18, RAMPZ_IO                       ; Save RAMPZ.

    out		RAMPZ_IO, r24                       ; Load RAMPZ with the MSB of the address.
    movw	r30,  r22                           ; Move low bytes of address to ZH:ZL from R23:R22
    elpm	r24,  Z								; load low byte

	in		r25, RAMPZ_IO						; RAMPZ to r25
	adiw	r30, 1								; increment address by 1
    adc		r25, r1								; add carry to tmp RAMPZ
	out		RAMPZ_IO, r25						; store tmp to RAMPZ
	elpm	r25, Z								; load high byte

	out		RAMPZ_IO, r18                       ; Restore RAMPZ register.
    ret                                         ; return from function
*/
/*******************************************************************************
Wait for completition SPM
Parameters:
  
Returns:
  
*******************************************************************************/
.global SP_WaitForCompletition

SP_WaitForCompletition:
	in		r18, SPMCSR_IO						; Load SPMCSR
	sbrc	r18, SPMEN								
	rjmp	SP_WaitForCompletition				; Jump if SPMEN in SPMCSR set
	ret

; eof sp_driver.s

